Popular Searches
Popular Course Categories
Popular Courses

Uncontrolled Components

Uncontrolled Components

React Forms

Uncontrolled Components in React JS

Uncontrolled Components are form elements in React JS whose current values are managed by the DOM rather than being controlled by React state. React can provide an initial value using attributes such as defaultValue and defaultChecked. When the user changes the input, the DOM maintains its current value.

React developers can access the current values of uncontrolled form elements using the useRef() Hook, DOM references, or the browser's FormData API when the form is submitted.

Uncontrolled components are useful for simple forms, file uploads, and situations where input values only need to be read when a form is submitted.

Course Link: JustAcademy React JS Training Course

Demo Link: Register for React JS Course Demo


1. What Are Uncontrolled Components?

An uncontrolled component is a form element whose current value is maintained by the browser's DOM. Unlike a controlled component, it does not require React state to be updated on every keystroke.

For example, a text input can have an initial value, but users can change it directly in the browser. React does not control the input's current value through a state variable.

Example

function NameForm() {
  return (
    <form>
      <label htmlFor="name">Enter your name:</label>
      <input
        id="name"
        name="name"
        type="text"
        defaultValue="Amit"
      />
    </form>
  );
}

export default NameForm;

In this example, the input initially displays "Amit". The user can edit the text, and the browser maintains the current value without using React state.


2. How Uncontrolled Components Work

Uncontrolled components rely on the DOM to maintain input values. React can specify the initial value, while the browser handles subsequent user edits.

  1. Render the input: Create a form element in JSX.
  2. Set an initial value: Use defaultValue or defaultChecked when needed.
  3. User changes the field: The browser updates the input's current value.
  4. Read the value: Use a ref or FormData when the value is needed.
  5. Process the form: Handle the form submission or perform another required action.

Basic Flow

React renders the form element
          ↓
Browser maintains the current input value
          ↓
User enters or changes information
          ↓
DOM stores the updated value
          ↓
React reads the value using a ref or FormData
          ↓
Application processes the form data

3. Understanding defaultValue

The defaultValue prop specifies the initial value of an uncontrolled text input or textarea. It does not continuously control the field after the element has mounted.

Example

function UsernameForm() {
  return (
    <div>
      <label htmlFor="username">Username:</label>
      <input
        id="username"
        name="username"
        type="text"
        defaultValue="Guest"
      />
    </div>
  );
}

export default UsernameForm;

The input initially displays "Guest". If the user changes it to "Rahul", the browser maintains "Rahul" as the current value. Changing the defaultValue prop after mounting does not control the current input value.

Important Points

  • defaultValue sets the initial value.
  • The browser maintains subsequent changes.
  • It is commonly used with uncontrolled text inputs and textareas.
  • Use value with state when React must control the current value.

4. Accessing Input Values Using useRef()

The useRef() Hook creates a reference that can point to a DOM element. By assigning the ref to an input's ref prop, you can read its current value when needed.

Syntax

const inputRef = useRef(null);

After React mounts the input, inputRef.current refers to the DOM input element. Its current text can be accessed through inputRef.current.value.

Example

import { useRef } from "react";

function NameForm() {
  const nameRef = useRef(null);

  function handleSubmit(event) {
    event.preventDefault();

    alert("Entered name: " + nameRef.current.value);
  }

  return (
    <form onSubmit={handleSubmit}>
      <label htmlFor="name">Name:</label>
      <input
        id="name"
        name="name"
        type="text"
        ref={nameRef}
        defaultValue="Amit"
      />
      <button type="submit">Submit</button>
    </form>
  );
}

export default NameForm;

How It Works

  1. useRef(null) creates a ref object.
  2. The ref prop connects the ref to the input element.
  3. The user enters or edits the name.
  4. When the form is submitted, nameRef.current.value reads the current value.
  5. The value can then be processed or sent to a backend.

5. Accessing Multiple Input Values with Refs

When a form contains several uncontrolled inputs, you can create a separate ref for each field. This approach is useful when values only need to be accessed at specific moments, such as form submission.

Example

import { useRef } from "react";

function RegistrationForm() {
  const nameRef = useRef(null);
  const emailRef = useRef(null);
  const phoneRef = useRef(null);

  function handleSubmit(event) {
    event.preventDefault();

    const formData = {
      name: nameRef.current.value,
      email: emailRef.current.value,
      phone: phoneRef.current.value
    };

    console.log(formData);
  }

  return (
    <form onSubmit={handleSubmit}>
      <input
        name="name"
        ref={nameRef}
        defaultValue=""
        placeholder="Full name"
      />
      <input
        name="email"
        type="email"
        ref={emailRef}
        defaultValue=""
        placeholder="Email address"
      />
      <input
        name="phone"
        type="tel"
        ref={phoneRef}
        defaultValue=""
        placeholder="Phone number"
      />
      <button type="submit">Register</button>
    </form>
  );
}

export default RegistrationForm;

Each ref provides access to its corresponding DOM element. When the form is submitted, the current values are collected into a JavaScript object.


6. Reading Form Values Using FormData

The browser's FormData API is another convenient way to read values from uncontrolled forms. It collects the values of form controls that have appropriate name attributes.

Example

function ContactForm() {
  function handleSubmit(event) {
    event.preventDefault();

    const formData = new FormData(event.currentTarget);

    const name = formData.get("name");
    const email = formData.get("email");

    console.log("Name:", name);
    console.log("Email:", email);
  }

  return (
    <form onSubmit={handleSubmit}>
      <label htmlFor="name">Name:</label>
      <input
        id="name"
        name="name"
        defaultValue=""
        required
      />

      <label htmlFor="email">Email:</label>
      <input
        id="email"
        name="email"
        type="email"
        defaultValue=""
        required
      />

      <button type="submit">Submit</button>
    </form>
  );
}

export default ContactForm;

How FormData Works

  • event.preventDefault() prevents the browser's default form navigation.
  • new FormData(event.currentTarget) collects the form's named field values.
  • formData.get("name") retrieves the value associated with the name field.
  • The collected values can be validated, displayed, or sent to a server.

Important: Every field you want to retrieve must have a suitable name attribute. Unchecked checkboxes are not included in the submitted FormData entries.


7. Uncontrolled Text Inputs

Uncontrolled text inputs are useful when the application only needs to read the entered value when an action occurs, rather than update React state on every keystroke.

Example

function SearchForm() {
  function handleSubmit(event) {
    event.preventDefault();

    const formData = new FormData(event.currentTarget);
    const searchTerm = formData.get("search");

    console.log("Search term:", searchTerm);
  }

  return (
    <form onSubmit={handleSubmit}>
      <input
        name="search"
        type="text"
        placeholder="Enter search term"
      />
      <button type="submit">Search</button>
    </form>
  );
}

export default SearchForm;

The browser maintains the input value. When the user submits the form, the application reads the search term using FormData.


8. Uncontrolled Textarea

A textarea collects multiline text such as comments, feedback, or descriptions. An uncontrolled textarea can use defaultValue to set its initial text.

Example

function FeedbackForm() {
  function handleSubmit(event) {
    event.preventDefault();

    const formData = new FormData(event.currentTarget);
    const feedback = formData.get("feedback");

    alert("Feedback: " + feedback);
  }

  return (
    <form onSubmit={handleSubmit}>
      <label htmlFor="feedback">Your Feedback:</label>
      <textarea
        id="feedback"
        name="feedback"
        defaultValue=""
        rows={4}
        placeholder="Write your feedback"
      />
      <button type="submit">Submit Feedback</button>
    </form>
  );
}

export default FeedbackForm;

The browser maintains the text entered by the user. The current value is read when the form is submitted.


9. Uncontrolled Select Dropdown

A select dropdown allows users to choose an option from a list. In an uncontrolled select element, defaultValue specifies the initially selected option.

Example

function CourseForm() {
  function handleSubmit(event) {
    event.preventDefault();

    const formData = new FormData(event.currentTarget);
    const course = formData.get("course");

    alert("Selected course: " + course);
  }

  return (
    <form onSubmit={handleSubmit}>
      <label htmlFor="course">Select Course:</label>
      <select
        id="course"
        name="course"
        defaultValue="react"
      >
        <option value="react">React JS</option>
        <option value="flutter">Flutter</option>
        <option value="selenium">Selenium</option>
      </select>
      <button type="submit">Submit</button>
    </form>
  );
}

export default CourseForm;

The dropdown initially selects React JS. Users can select a different option, and the current selection is read on submission.


10. Uncontrolled Checkboxes

An uncontrolled checkbox can use defaultChecked to specify its initial selection state. The browser maintains its current checked state after the user interacts with it.

Example

function TermsForm() {
  function handleSubmit(event) {
    event.preventDefault();

    const formData = new FormData(event.currentTarget);
    const accepted = formData.get("terms") === "accepted";

    alert(accepted ? "Terms accepted" : "Please accept the terms");
  }

  return (
    <form onSubmit={handleSubmit}>
      <label>
        <input
          type="checkbox"
          name="terms"
          value="accepted"
          defaultChecked={false}
        />
        I accept the terms and conditions
      </label>
      <button type="submit">Continue</button>
    </form>
  );
}

export default TermsForm;

In this example, the checkbox starts unchecked. If selected, its value is included in FormData. If it remains unchecked, the field is omitted.


11. Uncontrolled Radio Buttons

Radio buttons let users choose one option from a group. Uncontrolled radio buttons can use defaultChecked to set the initially selected option.

Example

function PaymentForm() {
  function handleSubmit(event) {
    event.preventDefault();

    const formData = new FormData(event.currentTarget);
    const payment = formData.get("payment");

    alert("Payment method: " + payment);
  }

  return (
    <form onSubmit={handleSubmit}>
      <label>
        <input
          type="radio"
          name="payment"
          value="card"
          defaultChecked
        />
        Card
      </label>
      <label>
        <input
          type="radio"
          name="payment"
          value="upi"
        />
        UPI
      </label>
      <button type="submit">Submit</button>
    </form>
  );
}

export default PaymentForm;

Both radio buttons share the same name, so the user can select only one option. The chosen value is read using FormData.


12. File Inputs in React

File inputs are commonly used for uploading images, documents, resumes, and other files. In React, a file input is treated as uncontrolled because its selected file value cannot be set programmatically like a normal text input.

Use a ref to access the DOM element and its files property, or read the selected file using FormData.

Example

import { useRef } from "react";

function FileUploadForm() {
  const fileRef = useRef(null);

  function handleSubmit(event) {
    event.preventDefault();

    const file = fileRef.current.files[0];

    if (!file) {
      alert("Please select a file.");
      return;
    }

    alert("Selected file: " + file.name);
  }

  return (
    <form onSubmit={handleSubmit}>
      <label htmlFor="document">Choose a document:</label>
      <input
        id="document"
        name="document"
        type="file"
        ref={fileRef}
      />
      <button type="submit">Upload</button>
    </form>
  );
}

export default FileUploadForm;

This example reads the selected file's name. It does not upload the file to a server. Actual uploads require additional handling, such as sending the file through a request using FormData.


13. Controlled vs. Uncontrolled Components

Both approaches can be used to create forms in React. The appropriate choice depends on how the application needs to manage and use the form values.

Feature Controlled Components Uncontrolled Components
Value management React state DOM
Common props value, checked defaultValue, defaultChecked
Reading values From state variables Using refs or FormData
State updates while typing Usually yes Not required
Live validation Convenient to implement Requires additional handling
Code complexity Can require more state and handlers Often simpler for basic forms
File inputs Cannot control the selected file value normally Commonly used with refs or FormData
Best suited for Forms with live feedback or state-dependent UI Simple forms whose values are read when needed

Controlled Example

const [name, setName] = useState("");

<input
  value={name}
  onChange={(event) => setName(event.target.value)}
/>

Uncontrolled Example

<input name="name" defaultValue="" />

In the controlled example, React state determines the current value. In the uncontrolled example, the browser maintains the current value.


14. Form Validation with Uncontrolled Components

Uncontrolled components can use built-in HTML validation attributes and custom validation when the form is submitted. Common attributes include required, minLength, maxLength, and suitable input types.

Example

function RegistrationForm() {
  function handleSubmit(event) {
    event.preventDefault();

    const formData = new FormData(event.currentTarget);
    const name = formData.get("name").trim();
    const email = formData.get("email");

    if (!name) {
      alert("Please enter your name.");
      return;
    }

    if (!email) {
      alert("Please enter your email.");
      return;
    }

    alert("Form validation completed.");
  }

  return (
    <form onSubmit={handleSubmit}>
      <input
        name="name"
        placeholder="Full name"
        required
      />
      <input
        name="email"
        type="email"
        placeholder="Email address"
        required
      />
      <button type="submit">Register</button>
    </form>
  );
}

export default RegistrationForm;

The browser checks the required fields and email format before normal form submission. The custom handler then reads and validates the submitted values. Client-side validation improves usability, but important rules must also be checked on the server.


15. Resetting an Uncontrolled Form

Uncontrolled forms can be reset using the browser's native form reset behavior. A reset restores the controls to their initial values, including values specified by defaultValue and defaultChecked.

Example

function ResetForm() {
  return (
    <form onSubmit={(event) => event.preventDefault()}>
      <input
        name="name"
        defaultValue="Amit"
        placeholder="Name"
      />
      <input
        name="email"
        type="email"
        defaultValue=""
        placeholder="Email"
      />
      <button type="submit">Submit</button>
      <button type="reset">Reset</button>
    </form>
  );
}

export default ResetForm;

Clicking Reset restores the name field to "Amit" and the email field to an empty string.


16. Common Mistakes in Uncontrolled Components

  • Using value when the intention is to create an uncontrolled input. Use defaultValue for an initial value.
  • Using checked instead of defaultChecked when you do not want React to control the checkbox or radio button.
  • Forgetting to provide a name attribute when reading values through FormData.
  • Trying to read a ref before React has attached the DOM element.
  • Assuming that changing defaultValue after mounting will update the current input value.
  • Forgetting event.preventDefault() when using a custom onSubmit handler to avoid the browser's default navigation.
  • Trying to set a file input's selected file value programmatically.
  • Assuming that data read from a form has already been saved to a database.
  • Relying only on client-side validation for important data.

17. Best Practices for Uncontrolled Components

  • Use uncontrolled components when values only need to be read at specific moments.
  • Use defaultValue for initial text or dropdown values.
  • Use defaultChecked for initial checkbox or radio selection.
  • Use refs for direct access to a particular DOM element.
  • Use FormData when reading several named fields during form submission.
  • Provide meaningful labels and suitable input types.
  • Use HTML validation attributes where appropriate.
  • Handle missing or invalid input values gracefully.
  • Validate important data on the server before saving or processing it.
  • Prefer controlled components if the UI must react immediately to changes in input values.

18. Mini Project: Student Registration Form

This project demonstrates an uncontrolled form using FormData to collect a student's name, email, and selected course.

App.jsx

function App() {
  function handleSubmit(event) {
    event.preventDefault();

    const formData = new FormData(event.currentTarget);
    const name = formData.get("name").trim();
    const email = formData.get("email");
    const course = formData.get("course");

    if (!name || !email || !course) {
      alert("Please complete all required fields.");
      return;
    }

    console.log({ name, email, course });
    alert("Registration form completed for " + name);
  }

  return (
    <main>
      <h1>Student Registration</h1>
      <form onSubmit={handleSubmit}>
        <label htmlFor="name">Full Name:</label>
        <input
          id="name"
          name="name"
          defaultValue=""
          required
        />

        <label htmlFor="email">Email Address:</label>
        <input
          id="email"
          name="email"
          type="email"
          defaultValue=""
          required
        />

        <label htmlFor="course">Select Course:</label>
        <select
          id="course"
          name="course"
          defaultValue=""
          required
        >
          <option value="">Choose a course</option>
          <option value="React JS">React JS</option>
          <option value="Flutter">Flutter</option>
          <option value="Selenium">Selenium</option>
        </select>

        <button type="submit">Register</button>
        <button type="reset">Reset</button>
      </form>
    </main>
  );
}

export default App;

Project Explanation

  1. Uncontrolled inputs: The form fields do not use React state for their current values.
  2. Initial values: The defaultValue prop defines the initial input or dropdown value.
  3. Form submission: The onSubmit handler reads the values.
  4. FormData: The API collects data using each field's name attribute.
  5. Validation: The code checks for missing fields before displaying a success message.
  6. Reset: The native reset button restores the initial form values.

Note: This project is for front-end learning. It does not save registration details permanently or send them to a backend.


19. Interview Questions and Answers

Q1. What is an uncontrolled component in React?

An uncontrolled component is a form element whose current value is maintained by the DOM rather than React state.

Q2. Which props are used to set initial values in uncontrolled components?

defaultValue is used for text inputs, textareas, and select elements. defaultChecked is used for checkboxes and radio buttons.

Q3. How do you access an uncontrolled input's value?

You can use a ref to read ref.current.value or use FormData when the form is submitted.

Q4. What is the use of useRef()?

The useRef() Hook creates a reference that can be used to access a DOM element or retain a value between renders without causing a re-render when the ref changes.

Q5. What is FormData?

FormData is a browser API that collects values from named form controls and can be used to read or submit form information.

Q6. What is the difference between value and defaultValue?

value controls the current value of a form element, usually through React state. defaultValue specifies the initial value of an uncontrolled field.

Q7. Can a file input be controlled like a normal text input?

No. A file input's selected files are controlled by the user through the browser. React applications commonly access them using refs or FormData.

Q8. When should you use uncontrolled components?

They are useful for simple forms when values only need to be read during submission, for file inputs, and for certain integrations with non-React code.

Q9. Do uncontrolled components support validation?

Yes. They support browser validation attributes and custom validation when values are read from the DOM or FormData.

Q10. Do uncontrolled components save data to a database automatically?

No. They only provide access to the input values. Saving data requires additional application logic and usually a backend or data service.


20. Practice Exercises

  1. Create an uncontrolled input for a user's name and read it using a ref.
  2. Build a contact form and read its fields using FormData.
  3. Create a feedback form using an uncontrolled textarea.
  4. Build a course dropdown using defaultValue.
  5. Create a checkbox for accepting terms and read its value during submission.
  6. Build a payment selection form using radio buttons.
  7. Create a file upload field and display the selected file name.
  8. Build a registration form with required-field validation.
  9. Add a Reset button that restores the form's initial values.
  10. Compare the same registration form implemented with controlled and uncontrolled components.

21. Revision Checklist

  • Understand the definition of uncontrolled components.
  • Know how the DOM maintains current form values.
  • Understand defaultValue and defaultChecked.
  • Know how to access input values using useRef().
  • Understand how to read form values using FormData.
  • Know how to handle text inputs, textareas, dropdowns, checkboxes, and radio buttons.
  • Understand why file inputs are generally uncontrolled.
  • Know how to validate and reset an uncontrolled form.
  • Understand the differences between controlled and uncontrolled components.
  • Practice the student registration form project.

22. Conclusion

Uncontrolled Components are a useful React JS technique for building forms in which the DOM maintains the current input values. React can provide initial values through defaultValue and defaultChecked, while refs and FormData allow applications to read the current values when required. Understanding uncontrolled components alongside controlled components helps developers choose the appropriate approach for each form and build practical React applications.

Learn more through the JustAcademy React JS Training Course.

To explore the course through a demo, visit Register for React JS Course Demo.

whatsapp